package com.qf.listener;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.config.DelayedConfig;
import com.qf.constant.CacheConstants;
import com.qf.constant.RabbitMQConstants;
import com.qf.feign.CacheFeign;
import com.qf.model.StandardReport;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

/*
 *@Description:
 *@author:刘哥
 *@Date:86180 2022/10/21 11:00
 */
@Component
@Slf4j
public class PushListener {
//    连接服务器对象
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private CacheFeign cacheFeign;
    @Autowired
    private ObjectMapper objectMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    //状态报告发送次数和时间: 1,2,3,4,5    立即推送,10s之后， 30s之后， 1min， 5min
    public  static  final String[] TTL={"0","10000","10000","10000","60000","60000","300000","300000","1200000","1200000"};

    /*
        监听推送队列,将推送队列的数据推送给用户服务器
     */
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void messageHandleri(StandardReport report, Channel channel, Message message) throws Exception {
//        获取客户端id
        long clientID = report.getClientID();
//        从redis里面或取客户端对象
        Map<String,String> clientMap = cacheFeign.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);

//        获取服务器地址(推送地址)
        String receivestatusual = clientMap.get("receivestatusual");
//        判断用户状态判断是否推送
        String isreturnstatus = clientMap.get("isreturnstatus");
//        判断如果需要推送,进行推送业务
        if(isreturnstatus != null && "1".equals(isreturnstatus)){
//          将推送的目的地地址放入report对象中
            report.setReceiveStatusUrl(receivestatusual);
//          记录推送次数
            report.setSendCount(1);
//            推送状态报告
            String result = sendReport(report);
//            手动ACK，
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
        }else {
//        如果不需要推送, 业务流程结束
            log.info("[接口模块 - 推送状态报告],用户不需要推送,业务完成");
        }

    }
    /**
     * 监听延时队列，接收到推送对象后，再次推送上次没有推送成功的消息
     * 监听延时队列状态报告, 推送
     *      * 除了第一次推送状态报告, 第N次都走这里
     *      * @param standardReport 状态报告对象
     */
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayerMessageHandler(Channel channel,Message message,StandardReport report) throws Exception {
//        调用发送方法再次发送到目标服务器
        String result = sendReport(report);
//        判断发送结果
        //3.返回手动ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

    }
    /**
     * 封装http请求对象
     * @param report
     * @return
     */
    private String sendReport(StandardReport report) throws Exception{
//        封装请求头
        HttpHeaders httpHeaders = new HttpHeaders();
//        指定传输的数据类型

        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
//        封装请求体
        String jsonBody = objectMapper.writeValueAsString(report);
        HttpEntity<String> entity = new HttpEntity<>(jsonBody,httpHeaders);

//        发送并接收返回数据
        try {
            String result=restTemplate.postForObject(report.getReceiveStatusUrl(),entity,String.class);
//            如果推送没有异常,南无判断是否发送成功
             isSuccess(report,result);
             return result;
        } catch (Exception e) {
            //        如果发送异常,将report数据存入延时队列过一会再发
            log.info("[接口模块 - 状态报告推送],推送异常,延时重新推送");
            sendReportToDelayedQueue(report);
            return null;
        }

    }
    /*
           延时发送{将消息发送到延时队列中,延时发送}
     */
    private void sendReportToDelayedQueue(StandardReport report){
//     判断发送次数,小于设定的次数继续发送
        if(report.getSendCount()<=7){
            report.setSendCount(report.getSendCount()+1);
//            设置发送消息,带延时功能,到时间就发送
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE,"routingKey",report, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
//                   设置延时时间
                    message.getMessageProperties().setExpiration(TTL[report.getSendCount()]);
                    return message;
                }
            });
        }else{
            log.info("[接口模块 - 状态推送报告],已经推送7次,用户没有返回,不在推送");
        }

//        发送延时消息到RabbitMQ的延时队列中,延时发出

//        如果消息大于7次,流程结束

    }

    /**
     * 判断验证发送结果的方法
     * 成功,流程结束
     * 失败,再次进入消息队列
     */
    public void isSuccess(StandardReport report,String result){
        if("SUCCESS".equalsIgnoreCase(result)){
            log.info("[接口模块-状态报告推送],用户已接受,推送完毕");
        }else {
            sendReportToDelayedQueue(report);
        }
    }
}
